/*
*
==============================================================================
*  Name        : 
*  Part of     : Omen Game Engine - DirectX 10 Plugin
*  Description : 
*  Version     : 1.0
*
*  Copyright (c) 2013 Lauri Kortevaara.
* 
==============================================================================
*/

#ifndef _DirectX_10__RENDERER_H_
#define _DirectX_10__RENDERER_H_

///////////////////////////////////////////////////////////////////////////////
// Omen Game Engine class                                               //
//                                                                           //
//                                                                           //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////
#define DIRECTX_10_PLUGIN_SOURCE 1

/// Omen Headers
#include "Config.h"
#include <IOmenKernel.h>
#include <IOmenShader.h>

#include "DirectX_10_Window.h"


/// DirectX 10 libraries for autolinking
#pragma comment(lib, "d3d10.lib")
#pragma comment(lib, "d3dx10.lib")
#pragma comment(lib, "dxgi.lib")

/// DirectX 10 Headers
#include <d3d10.h>
#include <d3dx10.h>

/// STL Headers
#include <map>
#include <string>

    struct DX_10_VertexType
    {
        D3DXVECTOR4 position;
        D3DXVECTOR4 normal;
        D3DXVECTOR2 texture;
    };


namespace Omen {

    class DirectX_10_Driver;
    class DirectX_10_Camera;
    class DirectX_10_Model;
    class DirectX_10_ColorShader;
    class DirectX_10_LightShader;
    class DirectX_10_Light;
    
    class Kernel;

/// DirectX_10_ renderer
  class DirectX_10_Renderer : public Omen::IRenderer
  {

    #define UUID_DirectX_10_Renderer "C2DA97B0-4ECC-4E54-BCED-5D7261CC24C7"

  public:
      virtual Omen_GUID classId() const { return OMEN_UUID(UUID_DirectX_10_Renderer); }  //

  public:
    DirectX_10_Renderer();
    
    virtual unsigned long windowHandle(void) const;

    /// Vertex and Index buffer interface of IOmenRenderer
    virtual void createVertexBuffer( IMesh* pMesh ) const; /// <summary>Renderer creates a vertex buffer for this mesh</summary>
    virtual void createIndexBuffer( IMesh* pMesh ) const;  /// <summary>Renderer creates an index buffer for this mesh</summary>
    virtual void setBuffers( Omen::IMesh* pMesh ) const;

    /// Shader factory function
    virtual bool createShader( const std::wstring& shaderName, Omen::IShader*& pShader ) const; /// <summary>Create a shader with given name</summary>
    
    /// Rendering interface of IOmenRenderer
    virtual void beginRendering() const;
    virtual void render(Omen::ICamera* pCamera) const;
    virtual void render(Omen::ILight** pLights, unsigned int numLights) const;
    virtual void render(Omen::IModel** pCameras, unsigned int numModels) const;
    virtual void endRendering() const;

    /// Refresh vertex and index buffers and create needed shader resources
    virtual void refreshRenderer(Omen::IModel** pCameras, unsigned int numModels);

    int WindowProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

    // ID3D10Device set/get
    void setDevice( ID3D10Device* pDevice) { m_device = pDevice; }
    ID3D10Device*           device() const { return m_device; }

    void initializeRenderer();

    // ID3D10RenderTargetView set/get
    void setRenderTargetView( ID3D10RenderTargetView* pRenderTargetView) { m_renderTargetView = pRenderTargetView; }
    ID3D10RenderTargetView* renderTargetView() const { return m_renderTargetView; }
    ID3D10RenderTargetView*& refRenderTargetView() { return m_renderTargetView; }

    // ID3D10DepthStencilView set/get
    void setDepthStencilView( ID3D10DepthStencilView* pDepthStencilView) { m_depthStencilView = pDepthStencilView; }
    ID3D10DepthStencilView* depthStencilView() const { return m_depthStencilView; }
    ID3D10DepthStencilView*& refDepthStencilView() { return m_depthStencilView; }

    // Stencil Buffer set/get
    void setDepthStencilBuffer( ID3D10Texture2D* pDepthStencilBuffer) { m_depthStencilBuffer = pDepthStencilBuffer; }
    ID3D10Texture2D* depthStencilBuffer() const { return m_depthStencilBuffer; }
    ID3D10Texture2D*& refDepthStencilBuffer() { return m_depthStencilBuffer; }

    // Stencil State set/get
    void setDepthStencilState( ID3D10DepthStencilState* pDepthStencilState) { m_depthStencilState = pDepthStencilState; }
    ID3D10DepthStencilState* depthStencilState() const { return m_depthStencilState; }
    ID3D10DepthStencilState*& refDepthStencilState() { return m_depthStencilState; }

    // Raster State set/get
    void setRasterState( ID3D10RasterizerState* pRaster) { m_rasterState; }
    ID3D10RasterizerState* rasterState() const { return m_rasterState; }
    ID3D10RasterizerState*& refRasterState() { return m_rasterState; }

    // IDXGISwapChain
    void setSwapChain( IDXGISwapChain* pSwapChain) { m_pSwapChain = pSwapChain; }
    IDXGISwapChain* swapChain() const { return m_pSwapChain; }

    // VSYNC
    void setVSyncEnabled( bool& bVSync ) { m_bVSyncEnabled = bVSync; }
    bool VSyncEnabled() const { return m_bVSyncEnabled; }

    // Back buffer
    ID3D10Texture2D*            backBuffer() const { return m_backBufferPtr; }
    ID3D10Texture2D*&           refBackBuffer() { return m_backBufferPtr; }

    // Projection, world and ortho matrices initialization
    void initializeMatrices();

    // IDXGI and ID3D10 stuff
    IDXGISwapChain*             m_pSwapChain;
    ID3D10Device*               m_device;
    ID3D10RenderTargetView*     m_renderTargetView;
    ID3D10Texture2D*            m_depthStencilBuffer;
    ID3D10DepthStencilState*    m_depthStencilState;
    ID3D10DepthStencilView*     m_depthStencilView;
    ID3D10RasterizerState*      m_rasterState;

    ID3DX10Font*                m_font;
    ID3DX10Sprite*              m_textSprite;
    ID3D10Texture2D*            m_backBufferPtr;

    mutable unsigned long       m_frameIndex;

    ///////////////////////////////////////////////////////////////////
    // OCTREE BUFFERS
    ///////////////////////////////////////////////////////////////////
    void createOctreeBuffers( IScene* pScene );
    void addOctreeBuffer( Omen::IOctreeNode* pNode );
    typedef struct  _octreeBuffer
    {
        ID3D10Buffer*               m_pOctreeVertices;
        unsigned long               m_octreeVerties;
        ID3D10Buffer*               m_pOctreeIndices;
        unsigned long               m_octreeIndices;
        unsigned int                m_depth;
    }OctreeBuffer;
    std::vector<OctreeBuffer>       m_listOctreeBuffers;
    ID3D10RasterizerState           *rasterizer_wireframe;
    void setOctreeBuffers(const OctreeBuffer& octreebuf) const;
    ///////////////////////////////////////////////////////////////////
    // ~OCTREE BUFFERS
    ///////////////////////////////////////////////////////////////////
    
    ///////////////////////////////////////////////////////////////////
    // AABB BUFFERS
    ///////////////////////////////////////////////////////////////////
    typedef struct  _BoundingBoxBuffer
    {
        ID3D10Buffer*               m_pVertices;
        unsigned long               m_numVertices;
        ID3D10Buffer*               m_pIndices;
        unsigned long               m_numIndices;
    }BoundingBoxBuffer;
    std::vector<BoundingBoxBuffer>  m_listBoundingBoxBuffers;
    
    void setBoundingBoxBuffers(const BoundingBoxBuffer& buffer) const;
    void createBoundingBoxBuffers( IScene* pScene );
    void addBoundingBoxBuffer( const AABB& box );
    ///////////////////////////////////////////////////////////////////
    // ~AABB BUFFERS
    ///////////////////////////////////////////////////////////////////

    // Projection, World and Orthogonal matrices
    D3DXMATRIX m_projectionMatrix;
    D3DXMATRIX m_worldMatrix;
    D3DXMATRIX m_orthoMatrix;

    mutable Omen::Matrix4x4     m_viewMatrix;

    DirectX_10_Window            m_window;
    double                       m_fieldOfView;
    double                       m_screenAspect;
    double                       m_screenNear, m_screenFar;

    mutable Omen::ICamera*       m_pCamera;
    DirectX_10_Model*            m_pModel;
    DirectX_10_Model*            m_pModel2;
    DirectX_10_ColorShader*      m_pColorShader;
    DirectX_10_LightShader*      m_pLightShader;
    DirectX_10_Light*            m_pLight;

    bool                         m_bVSyncEnabled;
    bool                         m_bOctreeVisible;
    bool                         m_bBoundingVolumesVisible;

    Omen::IMesh**                m_pListMeshes;
    unsigned long                m_maxNumMeshes;

    typedef std::map< const std::wstring, Omen::ITexture*> TexturesMap;
    mutable TexturesMap m_textures;
    typedef std::map< const std::wstring, Omen::IShader*> ShadersMap;
    mutable ShadersMap m_shaders;

    typedef struct _line
    {
        Omen::Vector3d p1, p2;
    } Line;
    
    std::vector<Line>           m_faceNormals;
  };

} // namespace Omen
#endif /// _DirectX_10__RENDERER_H_